package com.example.demo.service.impl;

import com.example.demo.domain.entity.Problem;
import com.example.demo.domain.entity.ProblemCategory;
import com.example.demo.domain.entity.ProblemType;
import com.example.demo.dto.ProblemCategoryDto;
import com.example.demo.mapper.ProblemCategoryMapper;
import com.example.demo.mapper.ProblemMapper;
import com.example.demo.service.ProblemService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
@Transactional
public class ProblemServiceImpl implements ProblemService {

    private static final Logger log = LoggerFactory.getLogger(ProblemServiceImpl.class);

    @Autowired(required = false)
    private ProblemMapper problemMapper;

    /**
     * 自动注入的optionDao对象.
     */
    @Autowired(required = false)
    private ProblemCategoryMapper problemCategoryMapper;

    @Override
    public List<Problem> getProblems() throws Exception {
        return problemMapper.findAllProblems();
    }
    @Override
    public List<ProblemType> getProblemType() throws Exception{
        return problemMapper.getProblemType();
    }

    @Override
    public List<Integer> getProblemByPaper(int paper_id) throws Exception {
        return problemMapper.getProblemByPaper(paper_id);
    }

    @Override
    public List<ProblemCategory> getAllCategory() {
        return problemCategoryMapper.getProblemCategories();
    }



    /**
     * [此方法仅供管理员使用]
     * 创建试题分类.
     * @param problemCategorySlug - 试题分类的别名
     * @param problemCategoryName - 试题分类的名称
     * @param parentProblemCategorySlug - 父级试题分类的别名
     * @return 包含试题分类创建结果的Map<String, Object>对象
     */
    public Map<String, Object> createProblemCategory(
            String problemCategorySlug, String problemCategoryName,
            String parentProblemCategorySlug, int showPriority) {
        int parentProblemCategoryId = getProblemCategoryIdUsingSlug(parentProblemCategorySlug);
        ProblemCategory problemCategory = new ProblemCategory(
                problemCategorySlug, problemCategoryName, parentProblemCategoryId);
        problemCategory.setShowPriority(showPriority);
        @SuppressWarnings("unchecked")
        Map<String, Object> result = (Map<String, Object>) getProblemCategoryCreationResult(problemCategory);

        if ( (boolean) result.get("isSuccessful") ) {
            problemCategoryMapper.createProblemCategory(problemCategory);

            long problemCategoryId = problemCategory.getProblemCategoryId();
            result.put("problemCategoryId", problemCategoryId);
        }
        return result;
    }



    /**
     * [此方法仅供管理员使用]
     * 编辑试题分类.
     * @param problemCategoryId - 试题分类的唯一标识符
     * @param problemCategorySlug - 试题分类的别名
     * @param problemCategoryName - 试题分类的名称
     * @return 包含试题分类编辑结果的Map<String, Boolean>对象
     */
    public Map<String, Boolean> editProblemCategory(
            int problemCategoryId, String problemCategorySlug,
            String problemCategoryName, int showPriority) {

        ProblemCategory problemCategory = new ProblemCategory();
        problemCategory.setProblemCategoryId(problemCategoryId);
        problemCategory.setProblemCategoryName(problemCategoryName);
        problemCategory.setProblemCategorySlug(problemCategorySlug);
        problemCategory.setShowPriority(showPriority);
        Map<String, Boolean> result = getProblemCategoryEditResult(problemCategory);

        if ( result.get("isSuccessful") ) {
            problemCategoryMapper.updateProblemCategory(problemCategory);
        }
        return result;
    }

    /**
     * 根据试题分类的唯一标识符删除某个试题分类.
     * @param problemCategoryId - 分类目录的唯一标识符
     * @return 试题分类是否被删除
     */
    public boolean deleteProblemCategory(int problemCategoryId) {
        boolean isProblemCategoryEditable = false;
        if ( isProblemCategoryEditable(problemCategoryId) ) {
            //先删除子分类
            List<ProblemCategory> subCategoryList = problemCategoryMapper.getProblemCategoryUsingCategoryParentId(problemCategoryId);
            for(ProblemCategory problemCategory : subCategoryList) {
                problemCategoryMapper.deleteProblemCategory(problemCategory.getProblemCategoryId());
            }
            problemCategoryMapper.deleteProblemCategory(problemCategoryId);
            isProblemCategoryEditable = true;
        }
        return isProblemCategoryEditable;
    }


    /**
     * 根据试题分类的别名获取试题分类的唯一标识符.
     * @param problemCategorySlug - 试题分类的别名
     * @return 试题分类的唯一标识符
     */
    private int getProblemCategoryIdUsingSlug(String problemCategorySlug) {
        int problemCategoryId = 0;
        if ( !problemCategorySlug.isEmpty() ) {
            ProblemCategory problemCategory = problemCategoryMapper.getProblemCategoryUsingCategorySlug(problemCategorySlug);

            if ( problemCategory != null ) {
                problemCategoryId = problemCategory.getProblemCategoryId();
            }
        }
        return problemCategoryId;
    }

    /**
     * 检查试题分类是否可编辑.
     * 试题分类的唯一标识符为1的项目是默认分类, 不可编辑.
     * @param problemCategoryId - 待编辑的试题分类对象
     * @return 试题分类是否可编辑
     */
    private boolean isProblemCategoryEditable(int problemCategoryId) {
        return problemCategoryId != 1;
    }



    /**
     * 检查欲创建的试题分类对象各字段的合法性.
     * @param problemCategory - 欲创建的试题分类对象
     * @return 包含试题分类对象各字段验证结果的Map<String, Boolean>对象
     */
    private Map<String, ? extends Object> getProblemCategoryCreationResult(ProblemCategory problemCategory) {
        Map<String, Boolean> result = new HashMap<>(6, 1);
        result.put("isProblemCategorySlugEmpty", problemCategory.getProblemCategorySlug().isEmpty());
        result.put("isProblemCategorySlugLegal", isProblemCategorySlugLegal(problemCategory.getProblemCategorySlug()));
        result.put("isProblemCategorySlugExists", isProblemCategorySlugExists(problemCategory.getProblemCategorySlug()));
        result.put("isProblemCategoryNameEmpty", problemCategory.getProblemCategoryName().isEmpty());
        result.put("isProblemCategoryNameLegal", isProblemCategoryNameLegal(problemCategory.getProblemCategoryName()));

        boolean isSuccessful = !result.get("isProblemCategorySlugEmpty") &&
                result.get("isProblemCategorySlugLegal") && !result.get("isProblemCategorySlugExists") &&
                !result.get("isProblemCategoryNameEmpty") &&  result.get("isProblemCategoryNameLegal");
        result.put("isSuccessful", isSuccessful);
        return result;
    }



    /**
     * 检查试题分类的别名的合法性
     * @param problemCategorySlug - 试题分类的别名
     * @return 试题分类的别名是否合法
     */
    private boolean isProblemCategorySlugLegal(String problemCategorySlug) {
        return problemCategorySlug.length() <= 32;
    }


    /**
     * 检查试题分类是否存在(检查Slug是否重复)
     * @param problemCategory - 当前的试题分类对象
     * @param problemCategorySlug - 试题分类的别名
     * @return 试题分类是否存在
     */
    private boolean isProblemCategorySlugExists(ProblemCategory problemCategory, String problemCategorySlug) {
        ProblemCategory anotherProblemCategory = problemCategoryMapper.getProblemCategoryUsingCategorySlug(problemCategorySlug);
        return anotherProblemCategory != null &&
                anotherProblemCategory.getProblemCategoryId() != problemCategory.getProblemCategoryId();
    }



    /**
     * 检查试题分类名称的合法性
     * @param problemCategoryName - 试题分类的名称
     * @return 试题分类名称是否合法
     */
    private boolean isProblemCategoryNameLegal(String problemCategoryName) {
        return problemCategoryName.length() <= 32;
    }

    /**
     * 获取试题分类的编辑结果.
     * @param problemCategory - 待编辑的试题分类对象
     * @return 包含试题分类编辑结果的Map<String, Boolean>对象
     */
    private Map<String, Boolean> getProblemCategoryEditResult(ProblemCategory problemCategory) {
        Map<String, Boolean> result = new HashMap<>();
        result.put("isProblemCategoryExists", isProblemCategoryExists(problemCategory.getProblemCategoryId()));
        result.put("isProblemCategoryEditable", isProblemCategoryEditable(problemCategory.getProblemCategoryId()));
        result.put("isProblemCategorySlugEmpty", problemCategory.getProblemCategorySlug().isEmpty());
        result.put("isProblemCategorySlugLegal", isProblemCategorySlugLegal(problemCategory.getProblemCategorySlug()));
        result.put("isProblemCategorySlugExists", isProblemCategorySlugExists(problemCategory, problemCategory.getProblemCategorySlug()));
        result.put("isProblemCategoryNameEmpty", problemCategory.getProblemCategoryName().isEmpty());
        result.put("isProblemCategoryNameLegal", isProblemCategoryNameLegal(problemCategory.getProblemCategoryName()));

        boolean isSuccessful = result.get("isProblemCategoryExists") &&
                !result.get("isProblemCategorySlugEmpty")  &&
                result.get("isProblemCategorySlugLegal")   &&
                !result.get("isProblemCategoryNameEmpty") &&  result.get("isProblemCategoryNameLegal");
        result.put("isSuccessful", isSuccessful);
        return result;
    }

    /**
     * 检查试题分类是否存在(检查Slug是否重复)
     * @param problemCategorySlug - 试题分类的别名
     * @return 试题分类是否存在
     */
    private boolean isProblemCategorySlugExists(String problemCategorySlug) {
        ProblemCategory problemCategory = problemCategoryMapper.
                getProblemCategoryUsingCategorySlug(problemCategorySlug);
        return problemCategory != null;
    }

    /**
     * 检查分类目录是否存在.
     * @param problemCategoryId - 分类目录的唯一标识符
     * @return 分类目录是否存在
     */
    private boolean isProblemCategoryExists(int problemCategoryId) {
        ProblemCategory problemCategory = problemCategoryMapper.getProblemCategoryUsingCategoryId(problemCategoryId);
        return problemCategory != null;
    }

}
